﻿#define INSTRUMENTATION

using System;

using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Silvermoon.Shapes;
using Silvermoon.Core;
using Silvermoon.Controls.Interfaces;
using System.Diagnostics;
using Silvermoon.Controls.Classes;
using Silvermoon.OpenGL;
using Silvermoon.Animations;
using Silvermoon.Windows;
using Silvermoon.Interfaces;
using Silvermoon.Controls.Base;
using Silvermoon.UI;
using System.Threading;


namespace Silvermoon.Controls
{
    /// <summary>
    /// Base class for all Controls.
    /// </summary>
    public abstract class Control : IPropertyObject, IDisposable, IStyleResource
    {
        /// <summary>
        /// Gets the number of controls which are currently allocated.
        /// </summary>
        public static int UsedControls { get; private set; }

        #region const

        public const int Opaque = 255;
        public const int Transparent = 0;

        #endregion
        #region ctor/dtor

        static Control()
        {

            VisualStateManager manager = new VisualStateManager(Control.OpacityDisabledEnabledGroup);
            VisualStateManager.RegisterClassManager(typeof(Control), manager);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Control"/> class.
        /// </summary>
        public Control()
            : base()
        {
            InvalidationMask = InvalidationFlag.All;
            OnControlCreated(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool dispose)
        {
            Unfocus();
            commands.Remove(Identity);
            RemoveAnimationStates();
            RemoveFromParent();
            ContextMenu = null;

            VisualStateManager.RemoveControlStateManager(this);
            DisposeControls();
            DisposeShapes();
            transformation = null;
            OnControlDisposed(this);
            RaiseEvent(DisposedEvent);
            if (sparseEvents != null) sparseEvents.Clear();
        }

        /// <summary>
        /// Disposes all child controls.
        /// </summary>
        private void DisposeControls()
        {
            ControlCollection controls = GetVisibleControls();
            if (controls != null)
            {
                controls.ClearAndDispose();
            }

        }

        /// <summary>
        /// Disposes all shapes.
        /// </summary>
        private void DisposeShapes()
        {
            ShapeCollection shapes = this.shapes;
            if (shapes != null)
            {
                Shape s = shapes.First;
                while (s != null)
                {
                    Shape next = s.NextShape;
                    s.NextShape = null;
                    s.Dispose();
                    s = next;
                }
                shapes.Clear();
                shapes = null;
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            this.ControlFlags |= ControlFlags.Disposing;
            Dispose(true);
            ControlFlags |= ControlFlags.Disposed;
        }

        protected void DisposeObject(IDisposable obj)
        {
            if (obj != null) obj.Dispose();
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="Control"/> is reclaimed by garbage collection.
        /// </summary>
        ~Control()
        {
            this.ControlFlags |= ControlFlags.Disposing;
            Dispose(false);
            ControlFlags |= ControlFlags.Disposed;
        }


        #endregion
        #region Fields

        private string styleName;

        /// <summary>
        /// provides a unique id for each control. This speeds up GetHashCode.
        /// </summary>
        private static int globalIdentity = 0;
        private static readonly Dictionary<int, ICommand> commands = new Dictionary<int, ICommand>();


        private Transformation transformation;

        /// <summary>
        /// Index that uniquely identifies the control.
        /// </summary>
        public readonly int Identity = globalIdentity++;

        private Projection projection;
        protected Color textColor = Color.Empty;

        public ControlFlags ControlFlags = ControlFlags.Visible | ControlFlags.Enabled | ControlFlags.HitTestVisible;

        protected Point location;
        protected Size size;
        private int opactiy = 255;
        private Margin margin;
        private Control parent;
        private ShapeCollection shapes;
        private PropertyAnimation propertyAnimation;
        private Dictionary<int, Delegate> sparseEvents;

        /// <summary>
        /// Gets or sets the StateManager to use.
        /// </summary>
        public VisualStateManager StateManager
        {
            get
            {
                return VisualStateManager.GetStateManager(this);
            }
            set
            {
                VisualStateManager.SetStateManager(this, value);
            }
        }

        public bool HasStateManager
        {
            get { return VisualStateManager.GetCustomStateManager(this) != null; }
        }


        #endregion
        #region Properties

        /// <summary>
        /// Gets or sets whether to raise a Tap event even if the event was previously handled. The default value is false.
        /// </summary>
        public bool AlwaysRaiseTapEvent
        {
            get { return (ControlFlags & ControlFlags.AlwaysRaiseTapEvent) != 0; }
            set { ControlFlags = value ? ControlFlags | ControlFlags.AlwaysRaiseTapEvent : ControlFlags & ~ControlFlags.AlwaysRaiseTapEvent; }
        }

        /// <summary>
        /// Gets the height of the control including it's top and bottom margin.
        /// </summary>
        public int PaddingHeight
        {
            get { return Margin.Height + Height; }
        }

        /// <summary>
        /// Gets the width of the control including it's left and right margin.
        /// </summary>
        public int PaddingWidth
        {
            get { return Margin.Width + Width; }
        }

        public virtual bool HasStyles { get { return false; } }

        public virtual StyleDictionary Styles { get { return null; } set { } }


        /// <remarks>
        /// Using a virtual property which is virtual and overriden at Window class is up to 3.65 times faster than doing a (c is Window), thats why this property is for.
        /// </remarks>
        protected virtual bool IsWindow { get { return false; } }

        /// <summary>
        /// Gets whether the control is on the screen.
        /// </summary>
        public bool IsOnScreen
        {
            get
            {
                Control c = this;
                while (c != null)
                {
                    if (!c.Visible) return false;
                    if (c.IsWindow) return true;
                    c = c.Parent;
                }
                return false;
            }
        }

        /// <summary>
        /// Sets the style for the control
        /// This is a write only property and is intended to apply the style within curly brace property declaration like
        /// new Button{ Color=Color.Green, Style=new MyButtonStyle()};
        /// </summary>
        public StyleBase Style
        {
            set
            {
                if (value != null) value.Apply(this);
            }
        }

        /// <summary>
        /// Gets or sets the name of the style to use for this control.
        /// </summary>
        public string StyleName
        {
            get { return styleName ?? string.Empty; }
            set
            {
                if (styleName != value)
                {
                    styleName = value;
                    if (parent == null) Invalidate(InvalidationFlag.NoStyleApplied);
                    else UpdateStyle();
                }
            }
        }

        /// <summary>
        /// Gets the client bounds with applied transformation.
        /// </summary>
        public Rectangle ActualBounds
        {
            get { return GetTransformedBounds(); }
        }

        public bool IsDisposing
        {
            get { return (ControlFlags & ControlFlags.Disposing) != 0; }
        }
        public bool IsDisposed
        {
            get { return (ControlFlags & ControlFlags.Disposed) != 0; }
        }

        /// <summary>
        /// Gets the window hosting this control.
        /// </summary>
        public Window Window
        {
            get { return GetWindow(); }
        }

        /// <summary>
        /// Gets a ShapeCollection that contains all shapes for this control.
        /// </summary>
        public ShapeCollection Shapes
        {
            get
            {
                if (shapes == null) shapes = new ShapeCollection();
                return shapes;
            }
        }

        /// <summary>
        /// Gets whether the control has been initialized.
        /// </summary>
        public bool IsInitialized
        {
            get
            {
                return !CheckFlag(InvalidationFlag.Uninitialized);
            }
            protected set
            {
                if (value) InvalidationMask &= ~InvalidationFlag.Uninitialized; else InvalidationMask |= InvalidationFlag.Uninitialized;
            }
        }

        /// <summary>
        /// Gets the child controls, otherwise null.
        /// </summary>
        internal protected ControlCollection VisibleControls
        {
            get { return GetVisibleControls(); }
        }

        /// <summary>
        /// Used for <see cref="T:ControlCollection"/> to implement linked lists.
        /// </summary>
        internal Control NextControl
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the parent controls.
        /// </summary>
        public Control Parent
        {
            get
            {
                return parent;
            }
            internal set
            {
                parent = value;
            }
        }

        /// <summary>
        /// Gets or sets the command to raise.
        /// This is a sparse property.
        /// </summary>
        public virtual ICommand Command
        {
            get
            {
                if ((ControlFlags & ControlFlags.Command) != 0)
                {
                    ICommand result;
                    if (commands.TryGetValue(Identity, out result)) return result;
                }
                return null;
            }
            set
            {
                if (value == null)
                {
                    if ((ControlFlags & ControlFlags.Command) != 0)
                    {
                        commands.Remove(Identity);
                    }
                }
                else commands[Identity] = value;
                ControlFlags = value != null ? ControlFlags | ControlFlags.Command : ControlFlags & ~ControlFlags.Command;
            }
        }


        /// <summary>
        /// Gets the Projection Matrix.
        /// This is usually used to apply transformations on demand, mostly from VisualStateManager.
        /// </summary>
        public Projection Projection
        {
            get
            {
                if (projection == null) projection = new Projection(this);
                return projection;
            }
        }

        /// <summary>
        /// Gets whether the control has been created which means it has been initialized once.
        /// This value returns false while the control is being created but not rendered.
        /// </summary>
        /// <remarks>
        /// This flags helps animations to decide wether to perform an animation. If this value returns false, no animation should be performed, 
        /// as the control itself is not even visible.
        /// </remarks>
        public bool Created
        {
            get
            {
                return !CheckFlag(InvalidationFlag.Uninitialized);
            }
        }

        /// <summary>
        /// Gets what parts are invalidated.
        /// </summary>
        public InvalidationFlag InvalidationMask
        {
            get;
            protected set;
        }


        /// <summary>
        /// Gets or sets the opacity value for the control in a range between 0 and 255 where 0 is transparent and 255 opaque.
        /// </summary>
        public int Opacity
        {
            get
            {
                return opactiy;
            }
            set
            {
                value = ValidateOpacity(value); if (value != opactiy)
                {
                    opactiy = value; Invalidate(InvalidationFlag.Alpha);
                }
            }
        }

        protected int ValidateOpacity(int value)
        {
            if (value < 0) return 0;
            if (value > 255) return 255;
            return value;
        }

        /// <summary>
        /// Gets whether the control is both visible and enabled.
        /// </summary>
        public bool IsVisibleAndEnabled
        {
            get
            {
                return (this.ControlFlags & (ControlFlags.Visible | ControlFlags.Enabled)) == (ControlFlags.Visible | ControlFlags.Enabled);
            }
        }

        /// <summary>
        /// Gets or sets whether the control can be hit.
        /// </summary>
        public bool IsHitTestVisible
        {
            get
            {
                return (ControlFlags & ControlFlags.HitTestVisible) != 0;
            }
            set
            {
                if (IsHitTestVisible != value)
                {
                    if (value) ControlFlags |= ControlFlags.HitTestVisible; else ControlFlags &= ~ControlFlags.HitTestVisible;
                }
            }
        }


        /// <summary>
        /// Gets or sets whether this control has enabled scrolling. If set to false, the control will not receive OnBeginScroll, OnScroll and OnEndScroll events.
        /// </summary>
        public bool CanPan
        {
            get
            {
                return (ControlFlags & ControlFlags.CanPan) != 0;
            }
            set
            {
                ControlFlags = value ? ControlFlags | ControlFlags.CanPan : ControlFlags & ~ControlFlags.CanPan;
            }
        }

        /// <summary>
        /// Occurs when a long press is detected.
        /// </summary>
        public bool IsHoldEnabled
        {
            get
            {
                return (ControlFlags & ControlFlags.EnableLongPress) != 0;
            }
            set
            {
                ControlFlags = value ? ControlFlags | ControlFlags.EnableLongPress : ControlFlags & ~ControlFlags.EnableLongPress;
            }
        }

        /// <summary>
        /// Gets or sets whether the control is enabled.
        /// </summary>
        public bool Enabled
        {
            get
            {
                return (ControlFlags & ControlFlags.Enabled) != 0;
            }
            set
            {
                if (Enabled != value)
                {
                    if (value) ControlFlags |= ControlFlags.Enabled; else ControlFlags &= ~ControlFlags.Enabled;
                    OnEnabledChanged();
                }
            }
        }

        /// <summary>
        /// Contains zero ore more transformations to apply for this control.
        /// Note that this has changed after Beta 2.0 from IEnumerable Transformations to Transformation to simplify usage:
        /// To add one ore more transformation to existing transformations, you can use the syntax "Control.Transformation += transformation;"
        /// and for removing you use "Control.Transformation -= transformation;".
        /// </summary>
        /// <remarks>
        /// You can use either += to add a new transformation at the tail of transformations, or |= to add it to the head of transformations.
        /// </remarks>
        public Transformation Transformation
        {
            get
            {
                return transformation;
            }
            set
            {
                if (transformation != value)
                {
                    transformation = value;
                    Invalidate(InvalidationFlag.Transformation);
                }
            }
        }

        /// <summary>
        /// Gets or sets the coordinates of the upper-left corner of the control relative to the upper-left corner of its container.
        /// </summary>
        public Point Location
        {
            get
            {
                return location;
            }
            set
            {
                if (location != value)
                {
                    location = value;
                    OnLocationChanged();
                }
            }
        }

        /// <summary>
        /// Gets the height of the area that represents the client area of the control.
        /// </summary>
        public int ClientHeight
        {
            get
            {
                return ClientBounds.Height;
            }
        }

        /// <summary>
        /// Gets the width of the area that represents the client area of the control.
        /// </summary>
        public int ClientWidth
        {
            get
            {
                return ClientBounds.Width;
            }
        }

        /// <summary>
        /// Gets the left offset of the area that represents the client area of the control.
        /// </summary>
        public int ClientLeft
        {
            get
            {
                return ClientBounds.Left;
            }
        }

        /// <summary>
        /// Gets the top area that represents the client area of the control.
        /// </summary>
        public int ClientTop
        {
            get
            {
                return ClientBounds.Top;
            }
        }

        /// <summary>
        /// Gets or sets the witdh of the control.
        /// </summary>
        public int Width
        {
            get
            {
                return Size.Width;
            }
            set
            {
                Size s = Size;
                s.Width = value;
                Size = s;
            }
        }

        /// <summary>
        /// Gets or sets the height of the control.
        /// </summary>
        public int Height
        {
            get
            {
                return Size.Height;
            }
            set
            {
                Size s = size;
                s.Height = value;
                Size = s;
            }
        }

        /// <summary>
        /// Gets or sets the height and width of the control.
        /// </summary>
        public virtual Size Size
        {
            get
            {
                return size;
            }
            set
            {
                if (size != value)
                {
                    Size s = size;
                    size = value;
                    OnSizeChanging(s);
                }
            }
        }

        /// <summary>
        /// Gets or sets the distance, in pixels, between the left edge of the control and the left edge of its container's client area.
        /// </summary>
        public int X
        {
            get
            {
                return location.X;
            }
            set
            {
                if (location.X != value)
                {
                    location.X = value;
                    OnLocationChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the distance, in pixels, between the top edge of the control and the top edge of its container's client area.
        /// </summary>
        public int Y
        {
            get
            {
                return location.Y;
            }
            set
            {
                if (location.Y != value)
                {
                    location.Y = value;
                    OnLocationChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the distance, in pixels, between the left edge of the control and the left edge of its container's client area.
        /// </summary>
        public int Left
        {
            get
            {
                return location.X;
            }
        }

        /// <summary>
        /// Gets or sets the distance, in pixels, between the top edge of the control and the top edge of its container's client area.
        /// </summary>
        public int Top
        {
            get
            {
                return location.Y;
            }
        }

        /// <summary>
        /// Gets the distance, in pixels, between the right edge of the control and the left edge of its container's client area.
        /// </summary>
        public int Right
        {
            get
            {
                return location.X + size.Width;
            }
        }

        /// <summary>
        /// Gets the distance, in pixels, between the bottom edge of the control and the top edge of its container's client area.
        /// </summary>
        public int Bottom
        {
            get
            {
                return location.Y + size.Height;
            }
        }

        ///// <summary>
        ///// Gets whether a control has changed it's surface and must be rendered again.
        ///// </summary>
        //public bool IsInitialized { get { return invalidMask == InvalidationFlag.None; } }

        /// <summary>
        /// Gets whether a control has become invalidated.
        /// </summary>
        public bool Invalidated
        {
            get
            {
                return InvalidationMask != InvalidationFlag.Empty;
            }
        }

        /// <summary>
        /// Gets the Screen.
        /// </summary>
        public Screen Screen
        {
            get
            {
                return Screen.Current;
            }
        }

        /// <summary>
        /// Gets or sets the bounds of the control.
        /// </summary>
        public Rectangle Bounds
        {
            get
            {
                Size size = Size;
                return new Rectangle(location.X, location.Y, size.Width, size.Height);
            }
            set
            {
                int w = Math.Max(value.Width, 0);
                int h = Math.Max(value.Height, 0);
                Size size = Size;
                if (size.Width != w || size.Height != h)
                {
                    Size s = size;
                    this.Size = new Size(w, h);
                }
                if (location.X != value.X || location.Y != value.Y)
                {
                    location = new Point(value.X, value.Y);
                    OnLocationChanged();
                }
            }
        }

        /// <summary>
        /// Gets the rectangle that represents the client area of the control.
        /// This is the rectangle 0,0,Width,Height including the values of <seealso cref="Margin"/>.
        /// </summary>
        public virtual Rectangle ClientBounds
        {
            get
            {
                Size size = Size;
                return new Rectangle(0, 0, size.Width, size.Height);
            }
        }

        public Margin Margin
        {
            get
            {
                return margin ?? Margin.Empty;
            }
            set
            {
                if (margin != value)
                {
                    margin = value;
                    OnMarginChanged();
                }
            }
        }

        public bool HasMargin { get { return margin != null && !margin.IsEmpty; } }

        public bool Visible
        {
            get
            {
                return (ControlFlags & ControlFlags.Visible) != 0;
            }
            set
            {
                if (Visible != value)
                {
                    ControlFlags = value ? ControlFlags | ControlFlags.Visible : ControlFlags & ~ControlFlags.Visible;
                    OnVisibleChanged();
                }
            }
        }

        public virtual Color Color
        {
            get { return Color.Empty; }
            set { }
        }

        /// <summary>
        /// Gets or set the text color for this and all child controls, if no child control has specified a TextColor other than Color.Empty.
        /// </summary>
        /// <remarks>
        /// This property is kinda special. It is not only bound to the owner control but to all child controls. This allows a host control to specify and change the text color
        /// for all child controls at once. for instance, imagine a ListView which has a ListViewItem. If the ListViewItem changed it's IsSelected property, the background color
        /// changes. In this case the text color of all child controls need to be changed either from black to white, since the contrast between black and blue (which is the default 
        /// selected ListViewItem color) would not be appropriate.
        /// </remarks>
        public Color TextColor
        {
            get
            {
                return textColor;
            }
            set
            {
                if (textColor != value)
                {
                    textColor = value;
                    OnTextColorChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the actual text color. This is the same value as <see cref="P:TextColor"/> except for Color.Empty. In this case the color is the first set color of the next ancestor./>
        /// </summary>
        public Color ActualTextColor
        {
            get { return GetActualTextColor(); }
            set
            {
                if (textColor != value)
                {
                    textColor = value;
                    OnTextColorChanged();
                }
            }
        }

        public bool IsTextColorEmpty
        {
            get { return textColor.IsEmpty; }
        }


        /// <summary>
        /// Gets whether either this control or any descendant control is focused.
        /// </summary>
        public virtual bool HasFocus
        {
            get
            {
                Control c = Screen.FocusedControl;
                if (c == null) return false;
                return c.IsDescendantOf(this);
            }
        }

        /// <summary>
        /// Gets whether this control is focused.
        /// </summary>
        public virtual bool IsFocused
        {
            get
            {
                return (ControlFlags & ControlFlags.Focused) != 0;
            }
            set
            {
                if (IsFocused != value)
                {
                    if (value) ControlFlags |= ControlFlags.Focused; else ControlFlags &= ~ControlFlags.Focused;
                    OnFocusChanged();
                }
            }
        }

        ///// <summary>
        ///// Gets or sets whether the control receives virtual OnPan events after a flick.
        ///// </summary>
        //public bool AllowVirtualPan
        //{
        //    get
        //    {
        //        return (ControlFlags & ControlFlags.AllowVirtualPan) != 0;
        //    }
        //    set
        //    {
        //        if (AllowVirtualPan != value)
        //        {
        //            if (value) ControlFlags |= ControlFlags.AllowVirtualPan; else ControlFlags &= ~ControlFlags.AllowVirtualPan;
        //        }
        //    }
        //}

        /// <summary>
        /// Gets  whether the control can receive focus.
        /// </summary>
        public virtual bool CanFocus
        {
            get
            {
                //return (Enabled & Visible && (ControlFlags & ControlFlags.CanFocus) != 0);
                return (Enabled & Visible);
            }
        }

        /// <summary>
        /// Specifies the default duration for final scrollings to a fixed endpoint.
        /// </summary>
        protected virtual int DefaultScrollDuration
        {
            get { return 350; }
        }

        /// <summary>
        /// Gets the client bounds of the control which are not overlapped by parts of a toolbar or keyboard.
        /// </summary>
        public virtual Rectangle ClientVisibleBounds
        {
            get
            {
                Rectangle bounds = ClientBounds;
                Window window = Window;
                if (window != null)
                {
                    Rectangle windowBounds = window.VisibleRect;
                    if (Parent != null) windowBounds.Location = PointToClient(windowBounds.Location);
                    int bottom = bounds.Bottom;
                    if (bounds.Y < windowBounds.Top)
                    {
                        bounds.Y = windowBounds.Top;
                    }
                    if (bottom > windowBounds.Bottom) bottom = windowBounds.Bottom;
                    bounds.Height = Math.Max(0, bottom - bounds.Top);
                }
                return bounds;
            }
        }

        /// <summary>
        /// Gets or sets the context menu for this control which appears when the control is touched and hold for a specific duration.
        /// </summary>
        public ContextMenuBase ContextMenu
        {
            get
            {
                return ((ControlFlags & ControlFlags.ContextMenu) != 0) ? ContextMenuBase.GetContextMenu(this) : null;
            }
            set
            {
                if (value != null)
                {
                    value.AddControl(this);
                }
                else
                {
                    ContextMenuBase contextMenu = ContextMenu;
                    if (contextMenu != null) contextMenu.RemoveControl(this);
                }
            }
        }


        #endregion
        #region Sparse events

        protected static readonly SparseEvent InitializedEvent = new SparseEvent();
        protected static readonly SparseEvent ShowContextMenuEvent = new SparseEvent();
        protected static readonly SparseEvent DoubleTapEvent = new SparseEvent();
        protected static readonly SparseEvent TapEvent = new SparseEvent();
        protected static readonly SparseEvent KeyDownEvent = new SparseEvent();
        protected static readonly SparseEvent KeyUpEvent = new SparseEvent();
        protected static readonly SparseEvent KeyPressEvent = new SparseEvent();
        protected static readonly SparseEvent TouchDownEvent = new SparseEvent();
        protected static readonly SparseEvent HoldEvent = new SparseEvent();
        protected static readonly SparseEvent TouchUpEvent = new SparseEvent();
        protected static readonly SparseEvent PanEvent = new SparseEvent();
        protected static readonly SparseEvent BeginPanEvent = new SparseEvent();
        protected static readonly SparseEvent DisposedEvent = new SparseEvent();

        protected static readonly SparseEvent CommandEvent = new SparseEvent();
        protected static readonly SparseEvent EnabledEvent = new SparseEvent();
        protected static readonly SparseEvent VisibleEvent = new SparseEvent();
        protected static readonly SparseEvent GotFocusEvent = new SparseEvent();
        protected static readonly SparseEvent LostFocusEvent = new SparseEvent();


        #endregion
        #region Events

        /// <summary>
        /// Occurs when the location has changed.
        /// </summary>
        protected virtual void OnLocationChanged()
        {
            //Invalidate(InvalidationFlag.Location);
            if (LocationChanged != null) LocationChanged(this, EventArgs.Empty);
            if (parent != null) parent.OnChildLocationChanged(this);
        }

        protected virtual void OnChildLocationChanged(Control child)
        {
        }

        /// <summary>
        /// Occurs when the size is changing
        /// </summary>
        /// <param name="oldValue">The old value of the size.</param>
        protected virtual void OnSizeChanging(Size oldValue)
        {
            InvalidationFlag flag = InvalidationFlag.None;
            if (oldValue.Width != size.Width) flag |= InvalidationFlag.Width;
            if (oldValue.Height != size.Height) flag |= InvalidationFlag.Height;
            InvalidationMask |= flag;
            if (parent != null) parent.OnChildSizeChanged(this, oldValue);
            OnSizeChanged();
        }

        /// <summary>
        /// Occurs when the size of the control has changed.
        /// Note: avoid to use this method to adjust the size or location of child controls or shapes. Rather use InitializeControls for that purpose.
        /// This is because OnSizeChanged would always be executed, while InitializeControl occurs only on demand. For instance, changing the Size of a control
        /// 5 time would call 5 times OnSizeChanged but only 1 time InitializeControls!
        /// </summary>
        protected virtual void OnSizeChanged()
        {
            Invalidate(InvalidationFlag.Size);
            if (SizeChanged != null) SizeChanged(this, EventArgs.Empty);
            EnsureRestStateOnSizeChanged();
        }

        protected virtual void EnsureRestStateOnSizeChanged()
        {
            if (CanPan)
            {
                EnsureRestState(false);
            }
        }

        /// <summary>
        /// Occurs when a command has raised on this or any child of this control.
        /// </summary>
        /// <param name="owner">Control that created the command.</param>
        /// <param name="command">The command that is raised.</param>
        ///<returns>True if bubbling or tunneling is canceled, otherwise false.</returns>
        internal protected virtual void OnCommand(CommandEventArgs args)
        {
            if (args.Handled) return;
            if (CommandRaised != null)
            {
                args.Sender = this;
                CommandRaised(this, args);
            }
            if (!args.Handled)
            {
                if (args.Command.Routing == RoutingStrategy.Bubble)
                {
                    Control parent = Parent;
                    if (parent != null)
                    {
                        args.Sender = this;
                        parent.OnCommand(args);
                    }
                }
            }
        }

        public void RaiseCommand(ICommand command)
        {
            CommandEventArgs args = new CommandEventArgs(command, this);
            OnCommand(args);
            if (!args.Handled)
            {
                command.Execute(this, args);
            }
        }

        #endregion
        #region Methods

        /// <summary>
        /// Measures the size that the control requires including margins.
        /// </summary>
        /// <param name="availableSize">The size which is available. If either Width or Height is 0, this indicated that infinite size is available for that part.</param>
        public virtual Size Measure(Size availableSize)
        {
            if (!Visible) return Size.Empty;
            Size size = this.Size;
            Margin m = this.Margin;
            int w = m.IsLeftEmpty || m.IsRightEmpty ? size.Width + m.Width : Math.Max(0, availableSize.Width + m.Width);
            int h = m.IsTopEmpty || m.IsBottomEmpty ? size.Height + m.Height : Math.Max(0, availableSize.Height - m.Height);
            return new Size(w, h);
        }

        public Window GetWindow()
        {
            Control c = this;
            while (c != null)
            {
                if (c.IsWindow) return (c as Window);
                c = c.Parent;
            }
            return null;
        }

        /// <summary>
        /// Suggests to dispose the control.
        /// </summary>
        public virtual void SuggestDispose()
        {
            Dispose();
        }

        private Color GetActualTextColor()
        {
            Color textColor = this.textColor;
            if (!textColor.IsEmpty) return textColor;
            Control p = parent;
            while (p != null && p.textColor.IsEmpty) p = p.Parent;
            return p != null ? p.textColor : Screen != null ? Screen.Renderer.StartTextColor : Color.Empty;
        }

        protected Color GetDownColor()
        {
            Color color = this.Color;
            if (!color.IsEmpty) return color;
            Control p = parent;
            while (p != null && p.Color.IsEmpty) p = p.Parent;
            return p != null ? p.Color : Color.Empty;

        }

        public virtual Rectangle GetToolTipAnchor()
        {
            return ClientBounds;
        }

        private Rectangle GetTransformedBounds()
        {
            Transformation t = transformation;
            if (t == null) return Bounds;
            Rectangle r = ClientBounds;
            t.AdjustBounds(ref r);
            Point p = location;
            r.Offset(p.X, p.Y);
            return r;
        }

        /// <summary>
        /// Occurs when the context menu shows up.
        /// </summary>
        protected virtual void OnShowContextMenu(object sender, EventArgs e)
        {
            RaiseEvent(ShowContextMenuEvent);
        }

        public void AddHandler(SparseEvent e, Delegate d)
        {
            int key = e.Key;
            if (sparseEvents == null)
            {
                sparseEvents = new Dictionary<int, Delegate>(2);
                sparseEvents.Add(key, d);
            }
            else
            {
                Delegate a;
                if (!sparseEvents.TryGetValue(key, out a))
                {
                    sparseEvents.Add(key, d);
                }
                else
                {
                    sparseEvents[key] = Delegate.Combine(a, d);
                }
            }
        }

        public void RemoveHandler(SparseEvent e, Delegate d)
        {
            if (sparseEvents != null)
            {
                int key = e.Key;
                Delegate a;
                if (sparseEvents.TryGetValue(key, out a))
                {
                    a = Delegate.Remove(a, d);
                    if (a == null)
                    {
                        sparseEvents.Remove(key);
                        if (sparseEvents.Count == 0) sparseEvents = null;
                    }
                }
            }
        }

        protected void RaiseEvent<T>(SparseEvent s, T e) where T : EventArgs
        {
            if (sparseEvents != null)
            {
                int key = s.Key;
                Delegate a;
                if (sparseEvents.TryGetValue(key, out a))
                {
                    var h = a as EventHandler<T>;
                    if (h != null) h(this, e);
                }
            }
        }

        protected void RaiseEvent(SparseEvent s)
        {
            if (sparseEvents != null)
            {
                int key = s.Key;
                Delegate a;
                if (sparseEvents.TryGetValue(key, out a))
                {
                    (a as EventHandler)(this, EventArgs.Empty);
                }
            }
        }

        protected void RaiseEvent(Control owner, SparseEvent s)
        {
            if (sparseEvents != null)
            {
                int key = s.Key;
                Delegate a;
                if (sparseEvents.TryGetValue(key, out a))
                {
                    (a as EventHandler)(owner, EventArgs.Empty);
                }
            }
        }

        protected EventHandler<T> GetHandler<T>(SparseEvent e) where T : EventArgs
        {
            if (sparseEvents == null) return null;
            Delegate a;
            int key = e.Key;
            if (sparseEvents.TryGetValue(key, out a))
            {
                return (a as EventHandler<T>);
            }
            return null;
        }

        protected EventHandler GetHandler(SparseEvent e)
        {
            if (sparseEvents == null) return null;
            Delegate a;
            int key = e.Key;
            if (sparseEvents.TryGetValue(key, out a))
            {
                return (a as EventHandler);
            }
            return null;
        }

        /// <summary>
        /// If overloaded, returns a ControlCollection used to store child controls.
        /// </summary>
        /// <returns>ControlCollection, otherwise null</returns>
        internal protected virtual ControlCollection GetVisibleControls()
        {
            return null;
        }

        internal protected virtual IEnumerable<Control> GetAttachedChildren()
        {
            return GetVisibleControls();
        }

        protected void SetState(string state)
        {
            OnStateChanged(state);
        }

        private void OnStateChanged(string state)
        {
            VisualStateManager.GoToState(this, state, IsInitialized);
        }

        protected virtual void OnVisibleChanged()
        {
            if (parent != null) parent.OnChildVisibleChanged(this);
            if (Visible)
            {
                // when a control is not visible, it'l never change it's IsInitialized state, therefore it must be changed at this place to ensure that it will be rendered after it has become visible:
                InvalidationMask &= ~InvalidationFlag.Visible;
            }
            else
            {
                RemoveDescendantFocus();
            }
            Invalidate(InvalidationFlag.Visible);
            RaiseEvent(VisibleEvent);
        }

        /// <summary>
        /// Occurs when a child control has changed it's Visible property.
        /// </summary>
        protected virtual void OnChildVisibleChanged(Control child)
        {
        }

        /// <summary>
        /// Removes the focus from any desendant control.
        /// </summary>
        protected void RemoveDescendantFocus()
        {
            Screen s = Screen;
            if (s != null)
            {
                Control c = s.FocusedControl;
                if (c != null)
                {
                    if (c.IsDescendantOf(this))
                    {
                        s.Focus(null);
                    }
                }
            }
        }

        protected virtual void OnEnabledChanged()
        {
            if (!Enabled) RemoveDescendantFocus();
            SetState(Enabled ? VState.Enabled : VState.Disabled);
            Invalidate(InvalidationFlag.Enabled);
            RaiseEvent(EnabledEvent);
        }

        /// <summary>
        /// Occurs directly before OnLayout. This is useful to ensure that some values are initialized on overridden OnLayout
        /// methods.
        /// </summary>
        protected virtual void PreLayout()
        {
        }

        /// <summary>
        /// Occurs when to layout all shapes and child controls.
        /// </summary>
        protected virtual void OnLayout()
        {
        }

        /// <summary>
        /// Occurs after PreLoad before InvalidationMask is reset.
        /// </summary>
        protected virtual void Loaded()
        {
        }

        /// <summary>
        /// Gets the style for the given control from any descendant, if available, otherwise null.
        /// </summary>
        /// <param name="c">Control for which to retreive a style.</param>
        /// <returns>Style, otherwise null.</returns>
        public StyleBase GetStyle(Control c)
        {
            Control host = this;
            while (host != null)
            {
                if (host.HasStyles)
                {
                    StyleBase style = host.Styles.GetStyle(c);
                    if (style != null) return style;
                }
                host = host.parent;
            }
            return null;
        }


        /// <summary>
        /// Occurs once when the control is initialized.
        /// </summary>
        protected virtual void OnInitialized()
        {
            RaiseEvent(InitializedEvent);
        }


        /// <summary>
        /// Occurs before the control is initialized, while IsInitialized is still set to false.
        /// The base functionality applies custom styles and call ApplyStyle.
        /// </summary>
        public virtual void PreInitialize()
        {
            UpdateStyle();
        }

        /// <summary>
        /// Updates the style.
        /// </summary>
        public void UpdateStyle()
        {
            StyleBase style = GetStyle(this);
            if (style != null) style.Apply(this);
            ApplyStyle();
        }


        /// <summary>
        /// Occurs the very first time before the control is rendered and after all properties are set and styles are applied.
        /// If overriden, this method determines to set properties like background with appropriate values if not set otherwise directly by setting the property or by a style.
        /// </summary>
        protected virtual void ApplyStyle()
        {
            InvalidationMask &= ~InvalidationFlag.NoStyleApplied;
        }

        /// <summary>
        /// Preload asures that possible rendering and data calculating is done. Calling PreLoad is a good idea to execute
        /// against each control that is not currently in the visible view to asure a fluent animation.
        /// </summary>
        /// <remarks>
        /// As a control developer, you need to assure that you preload any data by overriding PreLoad.
        /// </remarks>
        public void PreLoad()
        {
            if (Invalidated)
            {
                bool isNotInitialized = (this.InvalidationMask & InvalidationFlag.Uninitialized) != 0;
                if ((InvalidationMask & InvalidationFlag.NoStyleApplied) != 0) PreInitialize();
                while (InvalidationMask != InvalidationFlag.Empty)
                {
                    PreLayout();
                    OnLayout();
                    bool checkChildren = CheckFlag(InvalidationFlag.Size | InvalidationFlag.Margin | InvalidationFlag.Width | InvalidationFlag.Height | InvalidationFlag.UpdateChildren | InvalidationFlag.Layout);
                    InvalidationMask = InvalidationFlag.Empty;
                    LayoutShapes();
                    if (checkChildren) LayoutChildren();
                }

                // a child may invalidate the parent during PreLoad, for instance with the OnChildSizeChanged method therefor the parent is preloaded again
                // to avoid flickering:
                if (parent != null && parent.Invalidated) parent.PreLoad();

                Loaded();
                //                InvalidationMask = InvalidationFlag.Empty;
                if (isNotInitialized) OnInitialized();
            }

        }

        private void LayoutShapes()
        {
            if (shapes != null)
            {
                Shape s = shapes.First;
                while (s != null)
                {
                    if (s.Visible) s.PreLoad();
                    s = s.NextShape;
                }
            }
        }

        protected virtual void LayoutChildren()
        {
            if (VisibleControls != null)
            {
                IDecorator decorator = this as IDecorator;
                if (decorator != null && decorator.Control != null)
                {
                    Layouter.Layout(decorator.Control, Size);
                }
                else
                {
                    if (this is ICompositeControl)
                    {
                        Layouter.LayoutChildren(this);
                    }
                }
                Control c = VisibleControls.First;
                while (c != null)
                {
                    if (c.Visible) c.PreLoad();
                    c = c.NextControl;
                }
            }
        }

        /// <summary>
        /// Invalidates the control.
        /// </summary>
        /// <param name="flags">Flags what has invalidated.</param>
        public void Invalidate(InvalidationFlag flags)
        {
            InvalidationMask |= flags;
            Screen current = Screen.Current;
            if (current != null) current.Invalidate();
        }

        protected virtual void OnTextColorChanged()
        {
            Invalidate(InvalidationFlag.TextColor);
        }

        /// <summary>
        /// Sets the input focus to this control, if possible. If the control is not visible or not enabled, it will not receivce focus.
        /// </summary>
        public virtual void Focus()
        {
            if (CanFocus && Screen != null) Screen.Focus(this);
        }

        /// <summary>
        /// Removes the focus from this control if focused.
        /// </summary>
        public void Unfocus()
        {
            if (IsFocused && Screen != null) Screen.Focus(null);
        }

        /// <summary>
        /// Checks whether the specified <see cref="T:InvalidationFlag"/> is set.
        /// </summary>
        /// <param name="flag">The flag to check.</param>
        /// <returns>True, if set, otherwise false.</returns>
        public bool CheckFlag(InvalidationFlag flag)
        {
            return (InvalidationMask & flag) != 0;
        }

        /// <summary>
        /// Gets the boundaries of the control in absolute pixels relative to the screen.
        /// Note that this is a calculated value that can take a lot of recursive loops to determine, so cache it if possible!
        /// </summary>
        /// <returns>A rectangle that contains the screen boundaries.</returns>
        public Rectangle RectToScreen()
        {
            Point p = PointToScreen(this.Location);
            return new Rectangle(p.X, p.Y, Width, Height);
        }

        /// <summary>
        /// Captures an image of the current state of this control including all child controls.
        /// Dispose the texture that returns if it is no longer required to release texture memory!
        /// </summary>
        /// <returns>A texture that contains the image.</returns>
        public Texture Capture()
        {
            return Screen.Renderer.Capture(this);
        }

        /// <summary>
        /// Captures the current picture of the control including all child controls into a texture.
        /// </summary>
        /// <param name="backgroundColor">Background color to use to render this control.</param>
        /// <returns>Texture containing the image.</returns>
        public Texture Capture(Color backgroundColor)
        {
            return Screen.Renderer.Capture(this, backgroundColor);
        }

        /// <summary>
        /// Occurs when the control got the input focus.
        /// </summary>
        public virtual void OnGotFocus()
        {
            IsFocused = CanFocus;
            RaiseEvent(GotFocusEvent);
            //  BringIntoView(true);
        }

        protected virtual void CheckInputControl()
        {
            Window w = Window;
            if (w != null) w.IsKeyboardVisible = false;
        }

        /// <summary>
        /// Occurs when the control lost the input focus.
        /// </summary>
        public virtual void OnLostFocus()
        {
            IsFocused = false;
            RaiseEvent(LostFocusEvent);
        }

        //public override int GetHashCode()
        //{
        //    return Identity;
        //}

        //public override bool Equals(object obj)
        //{
        //    Control c = obj as Control;
        //    if (c == null) return false;
        //    return c.Identity == Identity;
        //}



        /// <summary>
        /// Ensures that the given rectangle is visible inside this control.
        /// </summary>
        /// <param name="bounds">The bounds to be visible.</param>
        public virtual void BringIntoView(Rectangle bounds, bool animated)
        {
            PreLayout();
            Control parent = Parent;
            if (parent != null)
            {
                bounds.Offset(X, Y);
                parent.BringIntoView(bounds, animated);
            }
        }

        /// <summary>
        /// Ensures that the control or parts of the control are visible in the none overlapped area of the screen.
        /// In case of a textbox this ensures the cursor to be visible.
        /// </summary>
        /// <param name="animated">True for animated transitions, otherwise false.</param>
        public virtual void BringIntoView(bool animated)
        {
            if (Parent != null)
            {
                Parent.BringIntoView(this.Bounds, animated);
            }
        }

        public void StartAnimations()
        {
            if (propertyAnimation != null)
            {
                PreLoad();
                propertyAnimation.Dequeue(this);
            }
        }

        /// <summary>
        /// Renders the control with all shapes and child controls to the specified renderer.
        /// Occurs  after transformations are applied.
        /// </summary>
        /// <param name="renderer">Renderer which will render the control.</param>
        internal protected virtual void OnRender(Renderer renderer)
        {
            ShapeCollection shapes = this.shapes;
            if (shapes != null) renderer.RenderShapes(shapes);
        }

        private void OnFocusChanged()
        {
            SetState(IsFocused ? VState.Focused : VState.Unfocused);
        }

        /// <summary>
        /// Converts a point in client coordinates to screen coordinates.
        /// </summary>
        /// <param name="client">Client coordinates relative to the left top corner of the parent control.</param>
        /// <returns>Point with screen coordinates.</returns>
        public Point PointToScreen(Point client)
        {
            Control parent = this.parent;
            client.Offset(X, Y);

            while (parent != null)
            {
                client.Offset(parent.X, parent.Y);
                parent = parent.Parent;
            }
            return client;
        }

        /// <summary>
        /// Convets a point in screen coordinates to client coordinates.
        /// </summary>
        /// <param name="screen">Screen corrdinates.</param>
        /// <returns>Point with client coordinates for this control relative to it's parent.</returns>
        public Point PointToClient(Point screen)
        {
            screen.Offset(-Left, -Top);
            Control parent = Parent;
            while (parent != null)
            {
                screen.Offset(-parent.X, -parent.Y);
                parent = parent.Parent;
            }
            return screen;
        }

        public bool IsDescendantOf(Control ancestor)
        {
            if (ancestor == null) return false;
            Control parent = Parent;
            while (parent != null)
            {
                if (parent == ancestor) return true;
                parent = parent.Parent;
            }
            return false;
        }

        public bool IsAncestorOf(Control descendant)
        {
            if (descendant == null) return false;
            Control parent = descendant.Parent;
            while (parent != null)
            {
                if (parent == this) return true;
                parent = parent.Parent;
            }
            return false;
        }

        /// <summary>
        /// Gets the rectangle that is not excluded by parent controls.
        /// </summary>
        /// <returns>Rectangle of clipped area relative to the parent.</returns>
        public Rectangle GetClipRect()
        {
            Rectangle bounds = Bounds;
            Control parent = Parent;
            Point offset = Location;
            while (parent != null)
            {
                Rectangle clip = parent.ClientBounds;
                bounds.Intersect(clip);
                Point loc = parent.Location;
                bounds.Offset(loc.X, loc.Y);
                offset.Offset(loc.X, loc.Y);
                parent = parent.Parent;
            }
            bounds.Offset(-offset.X, -offset.Y);
            return bounds;
        }

        public void RemoveFromParent()
        {
            Control parent = this.parent;
            if (parent != null && parent.VisibleControls != null) parent.VisibleControls.Remove(this);
        }

        /// <summary>
        /// Invokes the specified method within the main thread.
        /// </summary>
        /// <param name="method">Method to invoke</param>
        public void Invoke(ThreadStart method)
        {
            if (IsDisposing || IsDisposed) return;
            Screen s = Screen;
            if (s != null) s.InvokeThreaded(method);
        }

        /// <summary>
        /// Invokes the specified method to be executed after next rendering cycle.
        /// </summary>
        public void Schedule(ThreadStart method)
        {
            Screen.InvokeUnthreaded(method);
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return base.ToString() + " " + Identity;
        }

        /// <summary>
        /// Gets the scrolling offset.
        /// Usually, this is Point.Empty, but controls like ScrollViewer override this value to return their offsets to enable their descandants
        /// to determine the scrolling offset.
        /// </summary>
        /// <returns>Point with offset, otherwise Point.Empty</returns>
        protected virtual Point GetOffset()
        {
            return Point.Empty;
        }

        /// <summary>
        /// Gets the sum of all ancestor offsets.
        /// </summary>
        /// <returns>Point with the total offset.</returns>
        public Point GetTotalOffset()
        {
            Control parent = this.parent;
            Point offset = Point.Empty;
            while (parent != null)
            {
                Point p = parent.GetOffset();
                offset.Offset(p.X, p.Y);
                parent = parent.NextControl;
            }
            return offset;
        }

        internal protected virtual bool IgnoreTapHitTest()
        {
            return false;
        }

        [Conditional("INSTRUMENTATION")]
        static void OnControlCreated(Control c)
        {
            UsedControls++;
            if (ControlCreated != null) ControlCreated(c, EventArgs.Empty);
        }

        [Conditional("INSTRUMENTATION")]
        static void OnControlDisposed(Control c)
        {
            if (!c.IsDisposed) UsedControls--;
            if (ControlDisposed != null) ControlDisposed(c, EventArgs.Empty);
        }


        /// <summary>
        /// Occurs when the size of a child changed.
        /// </summary>
        /// <param name="child">Child contol which changed size.</param>
        protected virtual void OnChildSizeChanged(Control child, Size oldSize)
        {

        }

        #endregion
        #region Scale Methods

        // Scale Methods are by controls to scale their underlying <see cref="Shape"/>s and/or graphical rendering to fit the physical hardware screen size against the
        // designed size.

        public static int ScaleX(int x)
        {
            if (!Screen.IsScaled) return x;
            float scaleX = Screen.ControlScaleFactor.Width;
            return (int)(scaleX * x);
        }

        public static int ScaleY(int y)
        {
            if (!Screen.IsScaled) return y;
            float scaleY = Screen.ControlScaleFactor.Height;
            return (int)(scaleY * y);
        }

        public static int Scale(int xy)
        {
            if (!Screen.IsScaled) return xy;
            SizeF scale = Screen.ControlScaleFactor;
            return (int)(xy * scale.Width);
        }

        public static Size Scale(Size size)
        {
            if (!Screen.IsScaled) return size;
            SizeF scale = Screen.ControlScaleFactor;
            return new Size((int)(size.Width * scale.Width), (int)(size.Height * scale.Height));
        }

        public static Size Unscale(Size size)
        {
            if (!Screen.IsScaled) return size;
            SizeF scale = Screen.ControlScaleFactor;
            return new Size((int)(size.Width / scale.Width + 0.5f), (int)(size.Height / scale.Height + 0.5f));
        }


        public static Point Unscale(Point p)
        {
            if (!Screen.IsScaled) return p;
            SizeF scale = Screen.ControlScaleFactor;
            return new Point((int)(p.X / scale.Width + 0.5f), (int)(p.Y / scale.Height + 0.5f));
        }

        public static Point Scale(Point p)
        {
            if (!Screen.IsScaled) return p;
            SizeF scale = Screen.ControlScaleFactor;
            return new Point((int)(p.X * scale.Width + 0.5f), (int)(p.Y * scale.Height + 0.5f));
        }

        public static int UnscaleX(int x)
        {
            if (!Screen.IsScaled) return x;
            SizeF scale = Screen.ControlScaleFactor;
            return (int)(x / scale.Width + 0.5f);
        }

        public static int UnscaleY(int y)
        {
            if (!Screen.IsScaled) return y;
            SizeF scale = Screen.ControlScaleFactor;
            return (int)(y / scale.Height + 0.5f);
        }

        public static Size ScaledSize(int width, int height)
        {
            if (!Screen.IsScaled) return new Size(width, height);
            SizeF scale = Screen.ControlScaleFactor;
            return new Size((int)(scale.Width * width), (int)(scale.Height * height));
        }

        public static Point ScaledPoint(int x, int y)
        {
            if (!Screen.IsScaled) return new Point(x, y);
            SizeF scale = Screen.ControlScaleFactor;
            return new Point((int)(x * scale.Width), (int)(y * scale.Height));
        }

        public static Rectangle Scale(Rectangle bounds)
        {
            if (!Screen.IsScaled) return bounds;
            SizeF scale = Screen.ControlScaleFactor;
            float sX = scale.Width;
            float sY = scale.Height;
            return new Rectangle((int)(sX * bounds.X), (int)(sY * bounds.Y), (int)(sX * bounds.Width), (int)(sX * bounds.Height));
        }

        public static Rectangle Unscale(Rectangle bounds)
        {
            if (!Screen.IsScaled) return bounds;
            SizeF scale = Screen.ControlScaleFactor;
            float sX = scale.Width;
            float sY = scale.Height;
            return new Rectangle((int)(bounds.X / sX), (int)(bounds.Y / sY), (int)(bounds.Width / sX), (int)(bounds.Height / sY));
        }

        public static Rectangle ScaledRect(int x, int y, int w, int h)
        {
            if (!Screen.IsScaled) return new Rectangle(x, y, w, h);
            SizeF scale = Screen.ControlScaleFactor;
            float sX = scale.Width;
            float sY = scale.Height;
            return new Rectangle((int)(sX * x), (int)(sY * y), (int)(sX * w), (int)(sX * h));
        }

        public static Rectangle UnscaledRect(int x, int y, int w, int h)
        {
            if (!Screen.IsScaled) return new Rectangle(x, y, w, h);
            SizeF scale = Screen.ControlScaleFactor;
            float sX = scale.Width;
            float sY = scale.Height;
            return new Rectangle((int)(x / sX), (int)(y / sY), (int)(w / sX), (int)(h / sY));
        }

        //TODO: Implement this correctly.
        public static Margin ScaleMargin(int? left, int? top, int? right, int? bottom)
        {
            return new Margin(left, top, right, bottom);
        }


        #endregion
        #region Events

        public static event EventHandler ControlCreated;
        public static event EventHandler ControlDisposed;

        public event EventHandler<CommandEventArgs> CommandRaised;
        public event EventHandler LocationChanged;
        public event EventHandler SizeChanged;


        public event EventHandler EnabledChanged
        {
            add { AddHandler(EnabledEvent, value); }
            remove { RemoveHandler(EnabledEvent, value); }
        }


        public event EventHandler VisibleChanged
        {
            add { AddHandler(VisibleEvent, value); }
            remove { RemoveHandler(VisibleEvent, value); }
        }

        /// <summary>
        /// Occurs when the component is disposed by a call to the System.ComponentModel.Component.Dispose() method.
        /// </summary>
        public event EventHandler Disposed
        {
            add { AddHandler(DisposedEvent, value); }
            remove { RemoveHandler(DisposedEvent, value); }
        }

        /// <summary>
        /// Occurs when a key is pressed.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<System.Windows.Forms.KeyPressEventArgs> KeyPress
        {
            add
            {
                AddHandler(KeyPressEvent, value);
            }
            remove
            {
                RemoveHandler(KeyPressEvent, value);
            }
        }

        /// <summary>
        /// Occurs when a key is down.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<System.Windows.Forms.KeyEventArgs> KeyDown
        {
            add
            {
                AddHandler(KeyUpEvent, value);
            }
            remove
            {
                RemoveHandler(KeyDownEvent, value);
            }
        }

        /// <summary>
        /// Occurs when a key is up.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<System.Windows.Forms.KeyEventArgs> KeyUp
        {
            add
            {
                AddHandler(KeyUpEvent, value);
            }
            remove
            {
                RemoveHandler(KeyDownEvent, value);
            }
        }

        /// <summary>
        /// Occurs when the display is touched.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<TouchEventArgs> TouchDown
        {
            add
            {
                AddHandler(TouchDownEvent, value);
            }
            remove
            {
                RemoveHandler(TouchDownEvent, value);
            }
        }

        /// <summary>
        /// Occurs when the display is touched for period of time.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<TouchEventArgs> Hold
        {
            add
            {
                AddHandler(HoldEvent, value);
            }
            remove
            {
                RemoveHandler(HoldEvent, value);
            }
        }

        public event EventHandler<TapEventArgs> DoubleTap
        {
            add { AddHandler(DoubleTapEvent, value); }
            remove { RemoveHandler(DoubleTapEvent, value); }
        }

        /// <summary>
        /// Occurs when the display is no more touched.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<TouchEventArgs> TouchUp
        {
            add
            {
                AddHandler(TouchUpEvent, value);
            }
            remove
            {
                RemoveHandler(TouchUpEvent, value);
            }
        }

        /// <summary>
        /// Occurs when the context menu shows up.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler ShowContextMenu
        {
            add
            {
                AddHandler(ShowContextMenuEvent, value);
            }
            remove
            {
                RemoveHandler(ShowContextMenuEvent, value);
            }
        }

        /// <summary>
        /// Occurs when the touch point moves.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<PanEventArgs> BeginPan
        {
            add
            {
                AddHandler(BeginPanEvent, value);
            }
            remove
            {
                RemoveHandler(BeginPanEvent, value);
            }
        }

        /// <summary>
        /// Occurs when the touch point moves.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<PanEventArgs> Pan
        {
            add
            {
                AddHandler(PanEvent, value);
            }
            remove
            {
                RemoveHandler(PanEvent, value);
            }
        }

        public event EventHandler Initialized
        {
            add { AddHandler(InitializedEvent, value); }
            remove { RemoveHandler(InitializedEvent, value); }
        }

        /// <summary>
        /// Occurs when the display is tapped.
        /// This is a sparse event.
        /// </summary>
        public event EventHandler<TapEventArgs> Tap
        {
            add
            {
                AddHandler(TapEvent, value);
            }
            remove
            {
                RemoveHandler(TapEvent, value);
            }
        }

        public event EventHandler GotFocus
        {
            add
            {
                AddHandler(GotFocusEvent, value);
            }
            remove
            {
                RemoveHandler(GotFocusEvent, value);
            }
        }

        public event EventHandler LostFocus
        {
            add
            {
                AddHandler(LostFocusEvent, value);
            }
            remove
            {
                RemoveHandler(LostFocusEvent, value);
            }
        }

        #endregion
        #region Accessors

        public static readonly PropertyAccessor<Control, bool> VisibleProperty = PropertyAccessor.Register<Control, bool>("Visible", e => (e).Visible, (e, v) => (e).Visible = v);
        public static readonly PropertyAccessor<Control, bool> EnabledProperty = PropertyAccessor.Register<Control, bool>("Enabled", e => (e).Enabled, (e, v) => (e).Enabled = v);
        public static readonly PropertyAccessor<Control, int> WidthProperty = PropertyAccessor.Register<Control, int>("Width", e => (e).Width, (e, v) => (e).Width = v);
        public static readonly PropertyAccessor<Control, int> HeightProperty = PropertyAccessor.Register<Control, int>("Height", e => (e).Height, (e, v) => (e).Height = v);
        public static readonly PropertyAccessor<Control, int> OpacityProperty = PropertyAccessor.Register<Control, int>("Opacity", e => (e).opactiy, (e, v) => (e).Opacity = v);
        public static readonly PropertyAccessor<Control, Margin> MarginProperty = PropertyAccessor.Register<Control, Margin>("Margin", e => (e).Margin, (e, v) => (e).Margin = v);
        public static readonly PropertyAccessor<Control, Rectangle> BoundsProperty = PropertyAccessor.Register<Control, Rectangle>("Bounds", e => (e).Bounds, (e, v) => (e).Bounds = v);
        //public static readonly PropertyAccessor<Control, Projection> ProjectionProperty = PropertyAccessor.Register<Control, Projection>("Projection", e => (e).Projection, (e, v) =>
        //{
        //});
        public static readonly PropertyAccessor<Control, Color> TextColorProperty = PropertyAccessor.Register<Control, Color>("TextColor", e => (e).ActualTextColor, (e, v) => (e).ActualTextColor = v);
        public static readonly PropertyAccessor<Control, Color> ColorProperty = PropertyAccessor.Register<Control, Color>("Color", e => e.GetDownColor(), (e, v) => e.Color = v);
        public static readonly PropertyAccessor<Control, Size> SizeProperty = PropertyAccessor.Register<Control, Size>("Size", e => (e).Size, (e, v) => (e).Size = v);
        public static readonly PropertyAccessor<Control, Point> LocationProperty = PropertyAccessor.Register<Control, Point>("Size", e => (e).Location, (e, v) => (e).Location = v);


        public static readonly PropertyAccessor<Control, ScaleTransform> ScaleProperty = PropertyAccessor.Register<Control, ScaleTransform>(
            "Scale",
            e =>
            {
                ScaleTransform scale = e.Projection.Scale;
                return new ScaleTransform(scale.X, scale.Y, scale.Z);
            },
            (e, v) =>
            {
                ScaleTransform st = e.Projection.Scale;
                st.X = v.X;
                st.Y = v.Y;
                st.Z = v.Z;
                e.Invalidate(InvalidationFlag.Transformation);
            });


        public static readonly PropertyAccessor<Control, TranslateTransform> TranslateProperty = PropertyAccessor.Register<Control, TranslateTransform>(
                    "Translate",
                    e =>
                    {
                        TranslateTransform translate = e.Projection.Translate;
                        return new TranslateTransform(translate.X, translate.Y, translate.Z);
                    },
                    (e, v) =>
                    {
                        TranslateTransform st = e.Projection.Translate;
                        st.X = v.X;
                        st.Y = v.Y;
                        st.Z = v.Z;
                        e.Invalidate(InvalidationFlag.Transformation);
                    });

        // note: it's important, that DefaultDisabledEnabledGroup is located AFTER OpacityProperty. Otherwise it would have a value of null for Property!!
        public static readonly VisualStateGroup ColorDisabledEnabledGroup = new VisualStateGroup(
                VisualState.Enabled,
                new VisualState(VState.Disabled,
                    new ColorTransition(300, null, Color.Gray),
                    new ColorTransition(Control.TextColorProperty, 300, null, Color.LightGray),
                    new IntTransition(Control.OpacityProperty, 300, null, 190))
                );

        // note: it's important, that DefaultDisabledEnabledGroup is located AFTER OpacityProperty. Otherwise it would have a value of null for Property!!
        public static readonly VisualStateGroup OpacityDisabledEnabledGroup = new VisualStateGroup(
                new VisualState(VState.Enabled,
                    new IntTransition
                    {
                        To = 255,
                        Duration = 300,
                        Property = Control.OpacityProperty,
                        Tracking = TrackMode.Keep
                    }
                    ),

                new VisualState(VState.Disabled,
                    new IntTransition
                    {
                        To = 128,
                        Duration = 300,
                        Property = Control.OpacityProperty,
                        Tracking = TrackMode.Keep
                    }
            )
                );


        #endregion
        #region IMouseEventBehavior Members

        /// <summary>
        /// Occurs when the display is being touched.
        /// </summary>
        /// <param name="e">TouchEventArgs.</param>
        internal protected virtual void OnTouchDown(TouchEventArgs e)
        {
            bool handled = e.Handled;
            ProcessContextMenuOnTouch(e);

            RaiseEvent(TouchDownEvent, e);
            if (CanFocus && !e.FocusSet && !e.Cancel)
            {
                e.FocusSet = true;
                Focus();
            }
        }

        private void ProcessContextMenuOnTouch(TouchEventArgs e)
        {
            ContextMenuBase contextMenu = ContextMenu;
            if (contextMenu != null && contextMenu.Behavior == AppearBehavior.OnTouchDown)
            {
                OnShowContextMenu(this, e);
                contextMenu.Open(this);
            }
        }

        /// <summary>
        /// Occurs when touch and hold is detected. This appears when the display is touched over a period of time but not paned.
        /// </summary>
        /// <param name="e">TouchEventArgs.</param>
        internal protected virtual void OnHold(TouchEventArgs e)
        {
            ProcessContextMenuOnHold(e);

            RaiseEvent(HoldEvent, e);
        }

        private void ProcessContextMenuOnHold(TouchEventArgs e)
        {
            ContextMenuBase contextMenu = ContextMenu;
            if (contextMenu != null && contextMenu.Behavior == AppearBehavior.OnHold)
            {
                OnShowContextMenu(this, e);
                Schedule(() => contextMenu.Open(this));
                e.Cancel = true;
                e.Handled = false;
            }
        }

        /// <summary>
        /// Occurs when the display is no longer touched.
        /// e.IsTouched is set to false, when it is not physically touched, but set to true when it is still touched but controls should consider a non touched state, e.g.
        /// when swiping is detected.
        /// </summary>
        /// <param name="e">TouchEventArgs.</param>
        internal protected virtual void OnTouchUp(TouchEventArgs e)
        {

            if (IsFocused && !e.IsTouched)
            {
                CheckInputControl();
            }
            ProcessContextMenuOnTouchUp(e);
            RaiseEvent(TouchUpEvent, e);
        }

        private void ProcessContextMenuOnTouchUp(TouchEventArgs e)
        {
            ContextMenuBase contextMenu = ContextMenu;
            if (contextMenu != null) contextMenu.OnCancelOpening(this, e);
        }


        /// <summary>
        /// Occurs when the control is tapped.
        /// </summary>
        /// <param name="e">TapEventArgs.</param>
        internal protected virtual void OnTap(TapEventArgs e)
        {
            if (!e.Handled || AlwaysRaiseTapEvent)
            {
                RaiseEvent(TapEvent, e);
            }
        }

        /// <summary>
        /// Occurs when the control is tapped twice within a short period of time.
        /// </summary>
        /// <param name="e">TapEventArgs.</param>
        internal protected virtual void OnDoubleTap(TapEventArgs e)
        {
            RaiseEvent<TapEventArgs>(DoubleTapEvent, e);
        }

        #endregion
        #region IScrollEventBehavior Members

        /// <summary>
        /// Occurs  when the control is panned. This event does not bubble up to other controls.
        /// </summary>
        /// <param name="e">
        /// If e.AllowCancel is set to true, e.Cancel would abort to raise further OnPan methods.
        /// e.Value is the current value to be set.
        /// </param>
        internal protected virtual void OnPan(PanEventArgs e)
        {
            RaiseEvent<PanEventArgs>(PanEvent, e);
        }

        /// <summary>
        /// Occurs when a flick gesture is detected. This event does not bubble up to other controls.
        /// Note that OnFlick occurs directly before OnEndPan.
        /// </summary>
        /// <remarks>
        /// OnFlick occurs before OnEndPan for the following reason:
        /// OnFlick might decide to perform a scroll animation which would continue panning virtually. if OnEndPan would become before OnEndFlick,
        /// OnEndPan might have decided to hide a scrollbar and/or EnsureRestState, but immediately the OnFlick might continue. Therefore this is
        /// the appropriate order.
        /// </remarks>
        internal protected virtual void OnFlick(TouchEventArgs e)
        {
        }


        /// <summary>
        /// Occurs when the control is about to receive OnPan events. 
        /// This can be accepted by setting e.Handled to true, and aborted for all other controls by setting e.Cancel to true.
        /// This method is also the place to prepare for swiping, e.g. making a scrollbar visible.
        /// Set e.Value to a value that is the current value to be scrolled. e.g. for a scrollbar which scrolls YOffset property, e.Value would be set to new Point(0,YOffset).
        /// Set e.Handled to true to receive events at OnScroll method.
        /// </summary>
        /// <param name="e">ScrollEventArgs.</param>
        internal protected virtual void OnBeginPan(PanEventArgs e)
        {
            RaiseEvent<PanEventArgs>(BeginPanEvent, e);
        }

        /// <summary>
        /// Occurs when no further OnPan events will occur.
        /// This method bubbles through all controls at the specific touch point
        /// This method is also the place to undo preparations for swiping, e.g. hiding a scrollbar.
        /// Note that OnEndPan occurs directly after OnFlick
        /// </summary>
        internal protected virtual void OnEndPan(EventArgs e)
        {
        }

        /// <summary>
        /// Sets all properties to a defined value.
        /// If overridden, this method determines the ideal values of specific properties, for instance, when a property is changed as the
        /// uses swipes between possible values.
        /// It's best practice to access each property value  using PropertyAccessor.GetUnanimatedValue.
        /// </summary>
        /// <param name="animated">True when to allowed to tranistion to a new value, otherwise false.</param>
        public virtual void EnsureRestState(bool animated)
        {
        }

        #endregion
        #region IInputEventBehavior Members

        /// <summary>
        /// Occurs when a key is down.
        /// </summary>
        public virtual void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
        }

        /// <summary>
        /// Occurs when a key is up.
        /// </summary>
        public virtual void OnKeyUp(System.Windows.Forms.KeyEventArgs e)
        {

        }

        /// <summary>
        /// Occurs when a key is pressed.
        /// </summary>
        public virtual void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
        {
        }

        #endregion
        #region IPropertyObject Members

        private PropertyAnimation PropertyAnimation
        {
            get
            {
                if (propertyAnimation == null) propertyAnimation = new PropertyAnimation();
                return propertyAnimation;
            }
        }

        GroupTransitions IPropertyObject.GroupTransitions
        {
            get { return PropertyAnimation.GroupTransitions; }
            set { PropertyAnimation.GroupTransitions = value; }
        }

        /// <summary>
        /// Gets the typed <see cref="PropertyTracking"/> for the specified <see cref="PropertyAccessor"/>, otherwise null.
        /// </summary>
        /// <param name="property">PropertyAccessor for which to get the value.</param>
        /// <returns>Typed PropertyValue, otherwise null.</returns>
        PropertyTracking IPropertyObject.GetPropertyTracking(PropertyAccessor property)
        {
            var propertyValues = PropertyAnimation.Properties;
            PropertyTracking result;
            if (propertyValues.TryGetValue(property, out result)) return result;
            return null;

        }

        /// <summary>
        /// Sets or removes a typed <see cref="PropertyTracking"/> for a <see cref="PropertyAccessor"/>.
        /// </summary>
        /// <param name="property">PropertyAccessor for which to set the value.</param>
        /// <param name="value">PropertyValue to set, or null to remove an existing PropertyValue.</param>
        void IPropertyObject.SetPropertyTracking(PropertyAccessor property, PropertyTracking value)
        {
            if (value != null)
            {
                var propertyValues = PropertyAnimation.Properties;
                propertyValues[property] = value;
            }
            else
            {
                if (propertyAnimation != null)
                {
                    PropertyTracking tracking;
                    if (propertyAnimation.Properties.TryGetValue(property, out tracking))
                    {
                        tracking.Clear();
                        propertyAnimation.Properties.Remove(property);
                    }
                }
            }
        }

        void IPropertyObject.EnqueueAnimation(Animation a)
        {
            PropertyAnimation.Enqueue(a);
            Invalidate(InvalidationFlag.Transformation);
        }

        /// <summary>
        /// Removes all animated states.
        /// This method occurs when a control is disposing and should be called manually when a control is no longer in use to avoid unnecassary animations.
        /// </summary>
        public void RemoveAnimationStates()
        {
            if (propertyAnimation != null) propertyAnimation.Clear(this);
            propertyAnimation = null;
        }


        protected virtual void OnMarginChanged()
        {
            Invalidate(InvalidationFlag.Layout);
        }
        #endregion
    }
}
